/**
 * 全局错误处理中间件
 * 统一处理整个应用的错误和异常，提供一致的错误响应格式
 */

import { GameError, ErrorLevel, ErrorCategory, ERROR_CODES } from './ErrorTypes';
import { UnifiedLogger, ServiceLogger } from '../logging/UnifiedLogger';

/**
 * 错误处理配置
 */
export interface ErrorHandlerConfig {
    /** 是否在生产环境隐藏堆栈跟踪 */
    hideStackInProduction?: boolean;
    /** 是否记录所有错误到日志 */
    logAllErrors?: boolean;
    /** 错误通知配置 */
    notifications?: {
        /** 是否启用错误通知 */
        enabled: boolean;
        /** 通知的错误级别阈值 */
        threshold: ErrorLevel;
        /** 通知回调函数 */
        callback?: (error: GameError) => void;
    };
    /** 错误统计配置 */
    metrics?: {
        /** 是否启用错误统计 */
        enabled: boolean;
        /** 统计窗口大小（分钟） */
        windowSize: number;
    };
}

/**
 * 标准API响应格式
 */
export interface ApiResponse<T = any> {
    /** 是否成功 */
    success: boolean;
    /** 响应数据 */
    data?: T;
    /** 错误信息 */
    error?: {
        code: string;
        message: string;
        suggestion?: string;
        details?: any;
    };
    /** 时间戳 */
    timestamp: number;
    /** 请求ID */
    requestId?: string;
}

/**
 * 错误统计信息
 */
interface ErrorMetrics {
    /** 错误计数 */
    count: number;
    /** 最后发生时间 */
    lastOccurred: number;
    /** 错误详情 */
    samples: Array<{
        timestamp: number;
        code: string;
        message: string;
        context?: any;
    }>;
}

/**
 * 全局错误处理器
 */
export class GlobalErrorHandler {
    private static instance: GlobalErrorHandler;
    private logger: ServiceLogger;
    private config: ErrorHandlerConfig;
    private errorMetrics = new Map<string, ErrorMetrics>();
    private isInitialized = false;

    private constructor(config: ErrorHandlerConfig = {}) {
        this.config = {
            hideStackInProduction: true,
            logAllErrors: true,
            notifications: {
                enabled: false,
                threshold: ErrorLevel.ERROR
            },
            metrics: {
                enabled: true,
                windowSize: 60 // 60分钟窗口
            },
            ...config
        };
        
        this.logger = new ServiceLogger('GlobalErrorHandler');
    }

    /**
     * 获取单例实例
     */
    static getInstance(config?: ErrorHandlerConfig): GlobalErrorHandler {
        if (!this.instance) {
            this.instance = new GlobalErrorHandler(config);
        }
        return this.instance;
    }

    /**
     * 初始化全局错误处理
     */
    initialize(): void {
        if (this.isInitialized) {
            return;
        }

        this.setupGlobalHandlers();
        this.startMetricsCleanup();
        this.isInitialized = true;
        
        this.logger.info('Global error handler initialized', {
            metadata: { config: this.config }
        });
    }

    /**
     * 设置全局错误处理器
     */
    private setupGlobalHandlers(): void {
        // 处理未捕获的异常
        process.on('uncaughtException', (error: Error) => {
            const gameError = this.convertToGameError(error);
            this.handleCriticalError(gameError, 'uncaughtException');
        });

        // 处理未处理的Promise拒绝
        process.on('unhandledRejection', (reason: any) => {
            const error = reason instanceof Error ? reason : new Error(String(reason));
            const gameError = this.convertToGameError(error);
            this.handleCriticalError(gameError, 'unhandledRejection');
        });

        // 处理警告
        process.on('warning', (warning: Error) => {
            this.logger.warn('Process warning', undefined, {
                name: warning.name,
                message: warning.message,
                stack: warning.stack
            });
        });
    }

    /**
     * 处理致命错误
     */
    private handleCriticalError(error: GameError, source: string): void {
        this.logger.fatal(`Critical error from ${source}`, {
            metadata: { source }
        }, error.toJSON(), error);

        // 记录错误统计
        this.recordErrorMetrics(error);

        // 发送错误通知
        this.sendErrorNotification(error);

        // 在生产环境，给一些时间让日志写入后退出
        if (process.env.NODE_ENV === 'production') {
            setTimeout(() => {
                process.exit(1);
            }, 5000);
        }
    }

    /**
     * 处理API错误
     */
    handleApiError(error: any, requestId?: string): ApiResponse {
        const gameError = this.convertToGameError(error);
        
        // 记录错误
        this.logError(gameError, { requestId });
        
        // 记录统计
        this.recordErrorMetrics(gameError);
        
        // 发送通知（如果需要）
        this.sendErrorNotification(gameError);

        // 生成标准响应
        return this.createErrorResponse(gameError, requestId);
    }

    /**
     * 处理服务错误
     */
    handleServiceError(error: any, serviceName: string, methodName?: string): GameError {
        const gameError = this.convertToGameError(error, { serviceName, methodName });
        
        // 记录错误
        this.logError(gameError, { serviceName, methodName });
        
        // 记录统计
        this.recordErrorMetrics(gameError);
        
        return gameError;
    }

    /**
     * 转换普通错误为GameError
     */
    private convertToGameError(error: any, context?: any): GameError {
        if (error instanceof GameError) {
            // 更新上下文信息
            if (context) {
                error.context.serviceName = error.context.serviceName || context.serviceName;
                error.context.methodName = error.context.methodName || context.methodName;
            }
            return error;
        }

        if (error instanceof Error) {
            return GameError.fromError(error, ERROR_CODES.SYSTEM_SERVICE_UNAVAILABLE, context);
        }

        // 处理字符串错误
        if (typeof error === 'string') {
            return new GameError({
                code: ERROR_CODES.SYSTEM_SERVICE_UNAVAILABLE,
                message: error,
                level: ErrorLevel.ERROR,
                category: ErrorCategory.SYSTEM,
                context,
                userMessage: '系统发生错误，请稍后重试'
            });
        }

        // 处理其他类型的错误
        return new GameError({
            code: ERROR_CODES.SYSTEM_SERVICE_UNAVAILABLE,
            message: `Unknown error: ${JSON.stringify(error)}`,
            level: ErrorLevel.ERROR,
            category: ErrorCategory.SYSTEM,
            context,
            userMessage: '系统发生未知错误，请稍后重试'
        });
    }

    /**
     * 记录错误到日志
     */
    private logError(error: GameError, context?: any): void {
        if (!this.config.logAllErrors) {
            return;
        }

        const logContext = {
            ...context,
            metadata: {
                code: error.code,
                level: error.level,
                category: error.category,
                userMessage: error.userMessage,
                ...context
            }
        };

        switch (error.level) {
            case ErrorLevel.FATAL:
                this.logger.fatal(error.message, logContext, error.context, error);
                break;
            case ErrorLevel.ERROR:
                this.logger.error(error.message, logContext, error.context, error);
                break;
            case ErrorLevel.WARN:
                this.logger.warn(error.message, logContext, error.context);
                break;
            default:
                this.logger.info(error.message, logContext, error.context);
                break;
        }
    }

    /**
     * 记录错误统计
     */
    private recordErrorMetrics(error: GameError): void {
        if (!this.config.metrics?.enabled) {
            return;
        }

        const key = `${error.category}_${error.code}`;
        const existing = this.errorMetrics.get(key);
        
        if (existing) {
            existing.count++;
            existing.lastOccurred = Date.now();
            existing.samples.push({
                timestamp: Date.now(),
                code: error.code,
                message: error.message,
                context: error.context
            });
            
            // 保持最近10个样本
            if (existing.samples.length > 10) {
                existing.samples.shift();
            }
        } else {
            this.errorMetrics.set(key, {
                count: 1,
                lastOccurred: Date.now(),
                samples: [{
                    timestamp: Date.now(),
                    code: error.code,
                    message: error.message,
                    context: error.context
                }]
            });
        }
    }

    /**
     * 发送错误通知
     */
    private sendErrorNotification(error: GameError): void {
        if (!this.config.notifications?.enabled) {
            return;
        }

        if (error.level < this.config.notifications.threshold) {
            return;
        }

        if (this.config.notifications.callback) {
            try {
                this.config.notifications.callback(error);
            } catch (notificationError) {
                this.logger.error('Error notification callback failed', undefined, {
                    originalError: error.toJSON(),
                    notificationError: notificationError
                });
            }
        }
    }

    /**
     * 创建标准错误响应
     */
    private createErrorResponse(error: GameError, requestId?: string): ApiResponse {
        const shouldHideStack = this.config.hideStackInProduction && 
                               process.env.NODE_ENV === 'production';

        return {
            success: false,
            error: {
                code: error.code,
                message: error.userMessage,
                suggestion: error.suggestion,
                details: shouldHideStack ? undefined : {
                    originalMessage: error.message,
                    category: error.category,
                    level: error.level,
                    context: error.context,
                    stack: error.stack
                }
            },
            timestamp: Date.now(),
            requestId
        };
    }

    /**
     * 创建成功响应
     */
    createSuccessResponse<T>(data: T, requestId?: string): ApiResponse<T> {
        return {
            success: true,
            data,
            timestamp: Date.now(),
            requestId
        };
    }

    /**
     * 获取错误统计
     */
    getErrorMetrics(): Map<string, ErrorMetrics> {
        return new Map(this.errorMetrics);
    }

    /**
     * 清理过期的错误统计
     */
    private startMetricsCleanup(): void {
        if (!this.config.metrics?.enabled) {
            return;
        }

        const windowMs = (this.config.metrics.windowSize || 60) * 60 * 1000;
        
        setInterval(() => {
            const now = Date.now();
            
            for (const [key, metrics] of this.errorMetrics.entries()) {
                // 如果错误超过窗口期，移除统计
                if (now - metrics.lastOccurred > windowMs) {
                    this.errorMetrics.delete(key);
                } else {
                    // 清理过期的样本
                    metrics.samples = metrics.samples.filter(
                        sample => now - sample.timestamp <= windowMs
                    );
                }
            }
        }, 5 * 60 * 1000); // 每5分钟清理一次
    }

    /**
     * 生成错误报告
     */
    generateErrorReport(): {
        totalErrors: number;
        errorsByCategory: Record<string, number>;
        errorsByCode: Record<string, number>;
        topErrors: Array<{
            key: string;
            count: number;
            lastOccurred: number;
            recentSample: any;
        }>;
        reportTime: number;
    } {
        const errorsByCategory: Record<string, number> = {};
        const errorsByCode: Record<string, number> = {};
        let totalErrors = 0;

        for (const [key, metrics] of this.errorMetrics.entries()) {
            const [category, code] = key.split('_');
            
            totalErrors += metrics.count;
            errorsByCategory[category] = (errorsByCategory[category] || 0) + metrics.count;
            errorsByCode[code] = (errorsByCode[code] || 0) + metrics.count;
        }

        // 获取最频繁的错误
        const topErrors = Array.from(this.errorMetrics.entries())
            .sort(([, a], [, b]) => b.count - a.count)
            .slice(0, 10)
            .map(([key, metrics]) => ({
                key,
                count: metrics.count,
                lastOccurred: metrics.lastOccurred,
                recentSample: metrics.samples[metrics.samples.length - 1]
            }));

        return {
            totalErrors,
            errorsByCategory,
            errorsByCode,
            topErrors,
            reportTime: Date.now()
        };
    }

    /**
     * 重置错误统计
     */
    resetMetrics(): void {
        this.errorMetrics.clear();
        this.logger.info('Error metrics reset');
    }
}

/**
 * 全局错误处理器装饰器
 */
export function HandleErrors(errorHandler?: GlobalErrorHandler) {
    const handler = errorHandler || GlobalErrorHandler.getInstance();
    
    return function(target: any, propertyName: string, descriptor: PropertyDescriptor) {
        const method = descriptor.value;
        const serviceName = target.constructor.name;

        descriptor.value = async function(...args: any[]) {
            try {
                return await method.apply(this, args);
            } catch (error) {
                throw handler.handleServiceError(error, serviceName, propertyName);
            }
        };

        return descriptor;
    };
}

/**
 * API错误处理装饰器
 */
export function HandleApiErrors(errorHandler?: GlobalErrorHandler) {
    const handler = errorHandler || GlobalErrorHandler.getInstance();
    
    return function(target: any, propertyName: string, descriptor: PropertyDescriptor) {
        const method = descriptor.value;

        descriptor.value = async function(...args: any[]) {
            try {
                const result = await method.apply(this, args);
                return handler.createSuccessResponse(result);
            } catch (error) {
                return handler.handleApiError(error);
            }
        };

        return descriptor;
    };
}

/**
 * 全局错误处理器单例实例
 */
export const globalErrorHandler = GlobalErrorHandler.getInstance();
